package factory.excutor;

import factory.DatabaseInfo;
import factory.MapperStatement;
import factory.OperatorType;
import factory.jdbc.JdbcFactory;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.java.Log;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Log
public class DefaultExcutor {

    private DatabaseInfo databaseInfo;

    public DefaultExcutor (DatabaseInfo databaseInfo) {
        this.databaseInfo = databaseInfo;
    }

    /**
     * 执行方法的入口
     * @param mapperStatement
     * @return
     */
    public Object excute (MapperStatement mapperStatement, Object[] args) {

        String operateType = mapperStatement.getOperatorType();

        if (OperatorType.select.name().equals(operateType)) {
            return select(mapperStatement, args);
        }

        if (OperatorType.update.name().equals(operateType)) {
            return update(mapperStatement, args);
        }
        return null;
    }

    public Object select (MapperStatement mapperStatement, Object[] args) {
        // select * from user where id = #{id}
        Connection connection = JdbcFactory.getConnection(this.databaseInfo);
        String sql = mapperStatement.getSql();
        SqlEntiry sqlEntiry = sqlHandler(sql);

        try {
            PreparedStatement preparedStatement =  connection.prepareStatement(sqlEntiry.getExcuteSql());
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setString(i + 1, args[i] + "");
            }
            ResultSet resultSet = preparedStatement.executeQuery();

            Class clzz = Class.forName(mapperStatement.getResultType());
            Object obj = clzz.newInstance();
            while (resultSet.next()) {
                Field[] fields = clzz.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    if (field.getType().getName().equals("int") ) {
                        field.set(obj, resultSet.getInt(field.getName()));
                    }else {
                        field.set(obj, resultSet.getString(field.getName()));
                    }
                }
            }
            return obj;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object update (MapperStatement mapperStatement, Object[] args) {

        //update user set userName=#{userName} where id = #{id}
        Connection connection = JdbcFactory.getConnection(this.databaseInfo);
        String sql = mapperStatement.getSql();

        SqlEntiry sqlEntiry = sqlHandler(sql);

        PreparedStatement prepare;
        Object res = null;
        try {
            prepare = connection.prepareStatement(sqlEntiry.getExcuteSql());
        for (int i = 0; i < args.length; i++) {
            prepare.setString(i + 1, args[i] + "");
        }
            res = prepare.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return res;
    }

    /**
     * select * from user where id = ? and username = ?
     * #{id}#{userName}
     * @param sql
     * @return
     */
    private SqlEntiry sqlHandler (String sql) {
        List<String> parameters = new ArrayList<>();
        String regex = "#\\{(.+?)\\}";
        String str;
        Matcher matcher = Pattern.compile(regex).matcher(sql);
        while (matcher.find()) {
            str = matcher.group(0);
            String name = str.split("\\{")[1].split("\\}")[0];
            parameters.add(name);
        }
        String excuteSql = sql.replaceAll("#\\{.+?\\}", "?");

        SqlEntiry sqlEntiry = new SqlEntiry(sql, excuteSql, parameters);
        return sqlEntiry;
    }

    @Data
    @AllArgsConstructor
    class SqlEntiry {
        private String originSql;

        private String excuteSql;

        private List<String> parameterNames;
    }

    public static void main(String[] args) {
        String sql = "select * from user where id = #{id} and username = #{userName}";
        String[] sp = sql.split("#");
        System.out.println(sp);
        System.out.println(sql.replaceAll("#\\{.+?\\}", "?"));

        /*String str="总会在某一个回眸的时刻醉了流年，濡湿了柔软的心.总会有某一个回眸的时刻醉了流年，濡湿了柔软的心";
        str=str.replaceAll("总会在.+?流年", "总会有某一个回眸的时刻醉了流年");
        System.out.println(str);*/

        /*String regex = "#\\{(.+?)\\}";
        String str = "";
        Matcher matcher = Pattern.compile(regex).matcher(sql);
        while (matcher.find()) {
            str+= matcher.group(0);
        }
        System.out.println(str);*/

    }

}
